package com.ruoyi.framework.aspectj;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.Row;
import com.ruoyi.common.annotation.CheckUnique;
import com.ruoyi.common.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 优化版唯一校验切面
 */
@Aspect
@Component
public class UniqueCheckAspect {

    // 用于提取字段名的正则表达式（匹配由字母、数字、下划线组成的字段名）
    private static final Pattern FIELD_PATTERN = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]*");

    // 用于提取括号内容的正则表达式
    private static final Pattern BRACKET_PATTERN = Pattern.compile("\\(([^)]+)\\)");

    @Around("@annotation(checkUnique)")
    public Object checkUnique(ProceedingJoinPoint joinPoint, CheckUnique checkUnique) throws Throwable {
        // 获取方法参数
        Object[] args = joinPoint.getArgs();

        // 提取所有需要的字段值
        Map<String, Object> fieldValues = extractFieldValues(args, checkUnique.where());

        // 提取排除的ID值
        Object excludeId = extractExcludeId(args, checkUnique.excludeId());

        // 执行校验
        if (!fieldValues.isEmpty()) {
            String existsMess = checkExists(checkUnique, fieldValues, excludeId);
            if (null != existsMess) {
                throw new RuntimeException(existsMess);
            }
        }

        return joinPoint.proceed();
    }

    /**
     * 从方法参数中提取字段值
     */
    private Map<String, Object> extractFieldValues(Object[] args, String whereCondition) {
        Map<String, Object> fieldValues = new HashMap<>();

        // 从where条件中提取所有字段名
        java.util.Set<String> fieldNames = extractFieldNames(whereCondition);

        // 从参数中获取字段值
        for (String fieldName : fieldNames) {
            Object value = extractFieldFromObjects(args, fieldName);
            if (value != null) {
                fieldValues.put(fieldName, value);
            }
        }

        return fieldValues;
    }

    /**
     * 提取动态提示信息
     *
     * @param message 示例： {code:编码，name:名称}已存在
     * @return
     */
    private Map<String, String> extractMessage(String message) {
        // 提取大括号内的内容
        String content = ReUtil.get("\\{(.*?)\\}", message, 1);
        if (StringUtils.isEmpty(content)) return null;
        Map<String, String> resultMap = MapUtil.newHashMap();
        if (content != null) {
            // 分割键值对（支持中英文逗号）
            String[] pairs = content.split("[,，]\\s*");

            for (String pair : pairs) {
                // 分割键和值
                String[] keyValue = pair.split(":", 2);
                if (keyValue.length == 2) {
                    String key = keyValue[0].trim();
                    String value = keyValue[1].trim();
                    resultMap.put(key, value);
                }
            }
        }
        return resultMap;
    }

    /**
     * 从where条件中提取字段名
     */
    private java.util.Set<String> extractFieldNames(String whereCondition) {
        java.util.Set<String> fieldNames = new java.util.HashSet<>();

        // 提取普通字段名
        Matcher matcher = FIELD_PATTERN.matcher(whereCondition);
        while (matcher.find()) {
            String fieldName = matcher.group();
            // 排除SQL关键字
            if (!isSqlKeyword(fieldName)) {
                fieldNames.add(fieldName);
            }
        }

        // 提取括号内的字段名
        Matcher bracketMatcher = BRACKET_PATTERN.matcher(whereCondition);
        while (bracketMatcher.find()) {
            String bracketContent = bracketMatcher.group(1);
            Matcher innerMatcher = FIELD_PATTERN.matcher(bracketContent);
            while (innerMatcher.find()) {
                String fieldName = innerMatcher.group();
                if (!isSqlKeyword(fieldName)) {
                    fieldNames.add(fieldName);
                }
            }
        }

        return fieldNames;
    }

    /**
     * 判断是否为SQL关键字
     */
    private boolean isSqlKeyword(String word) {
        String upperWord = word.toUpperCase();
        return upperWord.equals("AND") || upperWord.equals("OR") ||
                upperWord.equals("WHERE") || upperWord.equals("SELECT") ||
                upperWord.equals("FROM") || upperWord.equals("INSERT") ||
                upperWord.equals("UPDATE") || upperWord.equals("DELETE");
    }

    /**
     * 提取排除的ID值
     */
    private Object extractExcludeId(Object[] args, String excludeIdField) {
        if (excludeIdField == null || excludeIdField.trim().isEmpty()) {
            return null;
        }
        return extractFieldFromObjects(args, excludeIdField);
    }

    /**
     * 从对象中提取字段值
     */
    private Object extractFieldFromObjects(Object[] args, String fieldName) {
        for (Object arg : args) {
            if (arg != null) {
                try {
                    // 尝试通过反射获取字段值
                    java.lang.reflect.Field field = arg.getClass().getDeclaredField(fieldName);
                    field.setAccessible(true);
                    return field.get(arg);
                } catch (NoSuchFieldException e) {

                    // 下划线转驼峰
                    fieldName = StrUtil.toCamelCase(fieldName);
                    // 如果字段不存在，尝试通过getter方法
                    String getterName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                    try {
                        java.lang.reflect.Method getter = arg.getClass().getMethod(getterName);
                        return getter.invoke(arg);
                    } catch (Exception ex) {
                        // 继续尝试其他对象
                    }
                } catch (Exception e) {
                    // 继续尝试其他对象
                }
            }
        }
        return null;
    }

    /**
     * 使用MyBatis-Flex检查数据是否已存在
     */
    private String checkExists(CheckUnique checkUnique, Map<String, Object> fieldValues, Object excludeId) {
        String mess = null;
        try {
            // 构建查询条件
            QueryWrapper queryWrapper = QueryWrapper.create()
                    .select()
                    .from(checkUnique.table());

            // 构建动态WHERE条件
            String dynamicWhere = "("+ buildDynamicWhere(checkUnique.where(), fieldValues)+")";
            queryWrapper.where(dynamicWhere);

            // 排除当前记录（更新操作）
            if (excludeId != null && !checkUnique.excludeId().isEmpty()) {
                queryWrapper.and(checkUnique.excludeId() + " != ?", excludeId);
            }

            // 逻辑删除条件
            if (!checkUnique.logicDelete().isEmpty()) {
                queryWrapper.and(checkUnique.logicDelete());
            }

            // 查询数据库数据
            Row row = Db.selectOneByQuery(queryWrapper);
            if(null == row) return null;
            Map<String, Object> exsitDataMap = row.toCamelKeysMap();
            // 提取动态信息提示
            Map<String, String> messMap = extractMessage(checkUnique.message());

            for (String key : fieldValues.keySet()) {
                Object cl = exsitDataMap.get(StrUtil.toCamelCase(key));

                if (fieldValues.get(key).equals(cl)) {
                    if (messMap == null) {
                        mess = checkUnique.message()+"已存在";
                    } else {
                        mess = messMap.getOrDefault(key, "");
                        mess += "已存在";
                    }
                }
            }
            return mess;
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }

    /**
     * 构建动态WHERE条件
     */
    private String buildDynamicWhere(String whereTemplate, Map<String, Object> fieldValues) {
        String result = whereTemplate;

        // 替换字段名为实际值
        for (Map.Entry<String, Object> entry : fieldValues.entrySet()) {
            String fieldName = entry.getKey();
            Object value = entry.getValue();

            // 将字段名替换为带参数占位符的条件
            String replacement;
            if (value instanceof String) {
                replacement = fieldName + " = '" + value + "'";
            } else {
                replacement = fieldName + " = " + value;
            }

            // 使用正则替换，确保只替换完整的字段名
            result = result.replaceAll("\\b" + fieldName + "\\b", replacement);
        }

        return result;
    }
}